home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / UI / Undo.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  59.2 KB  |  2,158 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Undo.cpp
  3.  
  4.     Contains:    Implementation for Undo class
  5.  
  6.     Owned by:    Nick Pilch
  7.  
  8.     Copyright:    © 1994 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <9>    16.12.1996    NP        1607071: Set done state to undone before
  13.                                     calling DisposeActionState on aborted
  14.                                     actions.
  15.          <8>     9/24/96    eeh        1315228: Verify part wrapper passed
  16.          <7>     8/13/96    VL        1372870: Not dispose of memory in
  17.                                     UndoAction destructor if process has gone
  18.                                     away. Added
  19.                                     SystemUndo::ShouldStackBeCleared to check
  20.                                     to see whether the first action(s) is still
  21.                                     valid.
  22.          <6>     6/18/96    NP        1267014, 1358481, 1347976, 1292558, 1266989
  23.          <5>     5/24/96    jpa        1246074: SOM_CATCH --> SOM_TRY..SOM_ENDTRY
  24.          <4>    .04.1996    NP        1316777: Machine hangs for one minute while
  25.                                     dragging. 1328995: Mem leak. 1323304:
  26.                                     actionData passed to part has _length == 0
  27.          <3>    .04.1996    NP        1316777: Partiall fix race condition with
  28.                                     the disposal notification process.
  29.  
  30.     To Do:
  31.         Remove destructors where not needed.
  32.     In Progress:
  33.         
  34. */
  35.  
  36.  
  37. #ifndef _PART_
  38. #include "Part.xh"
  39. #endif
  40.  
  41. //#ifndef _ORDCOLL_
  42. //#include "OrdColl.h"
  43. //#endif
  44.  
  45. #ifndef SOM_Module_OpenDoc_StdDefs_defined
  46. #include "StdDefs.xh"
  47. #endif
  48.  
  49. #ifndef _SEUTILS_
  50. #include "SEUtils.h"
  51. #endif
  52.  
  53. #ifndef _ODUTILS_
  54. #include "ODUtils.h"
  55. #endif
  56.  
  57. #ifndef _ITEXT_
  58. #include "IText.h"
  59. #endif
  60.  
  61. #define ODUndo_Class_Source
  62. #define VARIABLE_MACROS
  63. #include <Undo.xih>
  64.  
  65. #ifndef _EXCEPT_
  66. #include <Except.h>
  67. #endif
  68.  
  69. #ifndef _BARRAY_
  70. #include <BArray.h>
  71. #endif
  72.  
  73. //#ifndef _ODNEW_
  74. //#include <ODNew.h>
  75. //#endif
  76.  
  77. #ifndef _ODDEBUG_
  78. #include "ODDebug.h"
  79. #endif
  80.  
  81. //#ifndef _ODTYPES_
  82. //#include "ODTypes.h"
  83. //#endif
  84.  
  85. //#ifndef _PLFMDEF_
  86. //#include "PlfmDef.h"
  87. //#endif
  88.  
  89. //#ifndef _LIST_
  90. //#include "List.h"
  91. //#endif
  92.  
  93. #ifndef _ODMEMORY_
  94. #include "ODMemory.h"
  95. #endif
  96.  
  97. #ifndef __ERRORS__
  98. #include <Errors.h>
  99. #endif
  100.  
  101. #ifndef _ODDEBUG_
  102. #include "ODDebug.h"
  103. #endif
  104.  
  105. #ifndef _TEMPOBJ_
  106. #include <TempObj.h>
  107. #endif
  108.  
  109. #pragma segment ODUndo
  110.  
  111. /*
  112. IMPLEMENTATION NOTES
  113.  
  114. System Heap allocations
  115.  
  116. Almost all memory allocations occur in the system heap.
  117.  
  118. I'm trying to use as little system heap memory as possible because putting
  119. pointers into the system heap could be a bad idea (mem fragmentation).
  120.  
  121. UNDO AND REDO STACKS
  122.  
  123. The stacks are implemented with the UndoOrderedCollection class. The first item
  124. in the collection represents the top of the stack.
  125.  
  126. MARKING
  127.  
  128. When asked to mark a stack that is empty, nothing is done. The code that removes
  129. actions from a stack up to the last mark simply stops when it comes to the end
  130. of a stack.
  131.  
  132. ADDCLIENT, ETC.
  133.  
  134. We need to use these functions to ensure the SystemUndo is freed when
  135. the last OD document is closed. The memory associated with it will have gone
  136. away.
  137. */
  138.  
  139. //==============================================================================
  140. // Special new operator for the system heap that use NewPtrSys and
  141. //    DisposePtr.
  142. //==============================================================================
  143.  
  144. enum ODUndoMemoryAllocation
  145. {
  146.     kODSystemHeap
  147. };
  148.  
  149. void* operator new(size_t size, ODUndoMemoryAllocation allocation);
  150.  
  151. void* operator new(size_t size, ODUndoMemoryAllocation allocation)
  152. {
  153.     void*    retVal;
  154.  
  155.     if (allocation == kODSystemHeap)
  156.         retVal = NewPtrSys(size);
  157.     else
  158.         THROW(kODErrNotImplemented);
  159.     
  160.     return retVal;
  161. }
  162.  
  163. boolean IsValidProcess(ProcessSerialNumber* psn);
  164.  
  165. boolean IsValidProcess(ProcessSerialNumber* psn)
  166. {
  167.     ProcessInfoRec info;
  168.     info.processInfoLength = sizeof(ProcessInfoRec);
  169.     info.processName = nil;
  170.     info.processAppSpec = nil;
  171.         
  172.     return (GetProcessInformation(psn, &info) == noErr);
  173. }
  174.  
  175.  
  176. //==============================================================================
  177. // Temporarily include new UndoOrderedCollection class that I can allocate in the
  178. //    system heap. (May be longer than temporary.)
  179. //==============================================================================
  180.  
  181.  
  182.  
  183. /////////////// BEGIN TEMP HACK
  184.  
  185.  
  186.  
  187. //==============================================================================
  188. // UndoLink
  189. //==============================================================================
  190.  
  191. class  UndoLink {
  192.     public:
  193. //        void* operator new(size_t size) {return NewPtrSys(size);}
  194.         void operator delete(void* ptr) {DisposePtr((Ptr)ptr);}
  195.         UndoLink();
  196.         
  197.         UndoLink(UndoLink* next, UndoLink* previous);
  198.         
  199.         UndoLink( const UndoLink& );
  200.         
  201.         ~UndoLink();
  202.         
  203.         UndoLink* GetNext() const                    {return fNext;}
  204.         
  205.         UndoLink* GetPrevious() const                {return fPrevious;}
  206.     
  207.     // The following operations are provided for efficiency, but DO NOT USE THEM
  208.     // if there are any iterators active on a list. These operations don't bump
  209.     // the list's fSeed and the iterators will not be able to detect that they
  210.     // are out of sync!
  211.         
  212.         void  Remove( );
  213.         
  214.         void  AddBefore( UndoLink *aLink );
  215.         
  216.         void  AddAfter( UndoLink *aLink );
  217.     
  218.   //private-by-convention:
  219.           
  220.         void  SetNext(UndoLink* aLink)                {fNext = aLink;}
  221.         
  222.         void  SetPrevious(UndoLink* aLink)            {fPrevious = aLink;}
  223.  
  224.     private:
  225.     
  226.         UndoLink*        fNext;
  227.         UndoLink*        fPrevious;
  228. };
  229.  
  230.  
  231. //==============================================================================
  232. // UndoLinkedList
  233. //==============================================================================
  234.  
  235.  
  236. class UndoLinkedList {
  237.  
  238.     public:
  239.         void operator delete(void* ptr) {DisposePtr((Ptr)ptr);}
  240.           UndoLinkedList();
  241.           
  242.           ~UndoLinkedList();
  243.           
  244.           void            Remove(UndoLink&);
  245.           
  246.           void            AddFirst(UndoLink* link);
  247.           
  248.           UndoLink*            RemoveFirst();
  249.           
  250.           UndoLink*            First()                                            const;
  251.           
  252. protected:
  253.  
  254.         UndoLink            fSentinel;    // Marks the head & tail
  255.         ODULong            fSeed;        // Used to detect out-of-sync iterators
  256.         
  257.         UndoLink*            GetSentinel( )
  258.                                                 {return &fSentinel;}
  259.         const UndoLink*        GetSentinel( )                                    const
  260.                                                 {return &fSentinel;}
  261.         ODBoolean        IsSentinel( const UndoLink* link )                    const
  262.                                                 {return link==this->GetSentinel();}
  263.         ODBoolean        NotSentinel( const UndoLink* link )                    const
  264.                                                 {return link!=this->GetSentinel();}
  265.  
  266. private:                  
  267.         friend class UndoLinkedListIterator;
  268. };
  269.  
  270.  
  271. //=====================================================================================
  272. // UndoLinkedListIterator
  273. //=====================================================================================
  274.  
  275. class UndoLinkedListIterator {
  276.  
  277.     public:
  278.     
  279.         UndoLinkedListIterator(UndoLinkedList*    list);
  280.         
  281.         ~UndoLinkedListIterator();
  282.         
  283.         UndoLink*            First();
  284.         
  285.         UndoLink*            Next();
  286.  
  287.         ODBoolean         IsNotComplete();
  288.         
  289.     private:
  290.     
  291.         UndoLinkedList*        fList;
  292.         UndoLink*            fCurrent;
  293.         UndoLink*            fNext;        // Used only when deleting while iterating
  294.         UndoLink*             fPrevious;    // Used only when deleting while iterating
  295.         UndoLink*            fSentinel;
  296.         ODULong            fSeed;        // Used to detect out-of-sync iterators
  297.         
  298. };
  299.  
  300. //==============================================================================
  301. // Scalar Types
  302. //==============================================================================
  303.  
  304. typedef void* ElementType;
  305.  
  306. //=====================================================================================
  307. // Class UndoValueLink - Definition
  308. //=====================================================================================
  309.  
  310. class UndoValueLink : public UndoLink {
  311.     
  312. public:
  313.                             UndoValueLink(ElementType value);        
  314.                     ~UndoValueLink();
  315.         ElementType    GetValue()                        { return fValue;}
  316.      void        SetValue(ElementType v)            { fValue = v;}
  317.  
  318. private:
  319.     ElementType         fValue;
  320. };
  321.  
  322. //=====================================================================================
  323. // Class UndoOrderedCollection
  324. //=====================================================================================
  325.  
  326. class UndoOrderedCollection
  327. {
  328.     
  329. public:
  330.     void operator delete(void* ptr) {DisposePtr((Ptr)ptr);}
  331.     UndoOrderedCollection();
  332.     UndoOrderedCollection(ODUndoMemoryAllocation where);
  333.     ~UndoOrderedCollection();
  334.  
  335.      void    AddFirst(ElementType element);
  336.      ElementType    First();
  337.         // Returns kODNULL if there is no first element.
  338.      ElementType    RemoveFirst();
  339.         // Don't call if there are no elements. Crash will result.
  340.      void    Remove(ElementType existing);
  341.      void    RemoveAll();
  342.     
  343.         // Called from the destructor. Removes all elements, deleting the links
  344.         // Does not delete the elements themselves
  345.  
  346. protected:
  347.       UndoValueLink*     CreateNewLink(ElementType value) const;
  348.       ODBoolean    ElementsMatch(ElementType v1,ElementType v2) const;
  349.          // Does a pointer comparison by default 
  350.  
  351. private:
  352.     UndoLinkedList        fImplementation;
  353.     ODUndoMemoryAllocation    fHeap; // if kODNULL, use default heap.
  354.  
  355.     friend class UndoOrderedCollectionIterator;
  356.     friend class ListIterator;
  357. };
  358.  
  359. //=====================================================================================
  360. // Class UndoOrderedCollectionIterator
  361. //=====================================================================================
  362.  
  363. class UndoOrderedCollectionIterator {
  364. public:
  365.     UndoOrderedCollectionIterator(UndoOrderedCollection* collection);
  366.     ~UndoOrderedCollectionIterator();
  367.     ElementType    First();
  368.     ElementType    Next();
  369.     ODBoolean    IsNotComplete();
  370.     
  371. private:
  372.       UndoOrderedCollection*    fCollection;
  373.     UndoLinkedListIterator    fImplementation;
  374. };
  375.  
  376. //==============================================================================
  377. // UndoLink
  378. //==============================================================================
  379.  
  380.  
  381.  
  382. // Many of the simple link methods are inlines; see List.h for implementations.
  383.  
  384.  
  385. //------------------------------------------------------------------------------
  386. // UndoLink::UndoLink
  387. //
  388. // Constructor for UndoLink
  389. //------------------------------------------------------------------------------
  390.  
  391. UndoLink::UndoLink()                            
  392.     fNext = kODNULL; 
  393.     fPrevious = kODNULL;
  394. }
  395.  
  396. //------------------------------------------------------------------------------
  397. // UndoLink::UndoLink
  398. //
  399. // Constructor for UndoLink
  400. //------------------------------------------------------------------------------
  401.  
  402. UndoLink::UndoLink(UndoLink* next, UndoLink* previous)                            
  403.     fNext = next; 
  404.     fPrevious = previous;
  405. }
  406.  
  407. //------------------------------------------------------------------------------
  408. // UndoLink::UndoLink
  409. //
  410. // Copy constructor for UndoLink
  411. //------------------------------------------------------------------------------
  412.  
  413. UndoLink::UndoLink( const UndoLink &link )                            
  414.     fNext = link.fNext; 
  415.     fPrevious = link.fPrevious;
  416. }
  417.  
  418. //------------------------------------------------------------------------------
  419. // UndoLink::UndoLink
  420. //
  421. // Destructor for UndoLink
  422. //------------------------------------------------------------------------------
  423.  
  424. UndoLink::~UndoLink()                                            
  425. {
  426. }
  427.  
  428. //------------------------------------------------------------------------------
  429. // UndoLink::Remove
  430. //
  431. // Remove a link from its list (if any). DO NOT call this directly if there are
  432. // any iterators active on the list; use UndoLinkedList::Remove instead.
  433. //------------------------------------------------------------------------------
  434.  
  435. void    UndoLink::Remove( )
  436. {
  437.     if( fPrevious )
  438.         fPrevious->SetNext(fNext);
  439.     if( fNext )
  440.         fNext->SetPrevious(fPrevious);
  441.     fNext = kODNULL;
  442.     fPrevious = kODNULL;
  443. }
  444.  
  445. //------------------------------------------------------------------------------
  446. // UndoLink::AddBefore
  447. //
  448. // Add a link to a list before another link. It must not already be on any list.
  449. // DO NOT call this directly if there are any iterators active on the list;
  450. // use UndoLinkedList::Remove instead.
  451. //------------------------------------------------------------------------------
  452.  
  453. void    UndoLink::AddBefore( UndoLink *link )
  454. {
  455.     ASSERT(link!=kODNULL,paramErr);
  456.     WASSERT(fNext==kODNULL);
  457.     WASSERT(fPrevious==kODNULL);
  458.     fNext = link;
  459.     fPrevious = link->GetPrevious();
  460.     fPrevious->SetNext(this);
  461.     fNext->SetPrevious(this);
  462. }
  463.  
  464. //------------------------------------------------------------------------------
  465. // UndoLink::AddAfter
  466. //
  467. // Add a link to a list after another link. It must not already be on any list.
  468. // DO NOT call this directly if there are any iterators active on the list;
  469. // use UndoLinkedList::Remove instead.
  470. //------------------------------------------------------------------------------
  471.  
  472. void    UndoLink::AddAfter( UndoLink *link )
  473. {
  474.     ASSERT(link!=kODNULL,paramErr);
  475.     WASSERT(fNext==kODNULL);
  476.     WASSERT(fPrevious==kODNULL);
  477.     fPrevious = link;
  478.     fNext = link->GetNext();
  479.     fPrevious->SetNext(this);
  480.     fNext->SetPrevious(this);
  481. }
  482.  
  483. //======================================================================================
  484. // Class UndoLinkedList
  485. //======================================================================================
  486.  
  487. //------------------------------------------------------------------------------
  488. // UndoLinkedList::UndoLinkedList
  489. //
  490. // Constructor for UndoLinkedList
  491. //------------------------------------------------------------------------------
  492.  
  493. UndoLinkedList::UndoLinkedList()
  494.     :fSentinel(&fSentinel,&fSentinel),
  495.      fSeed(0)
  496. {
  497. }
  498.  
  499. //------------------------------------------------------------------------------
  500. // UndoLinkedList::~UndoLinkedList
  501. //
  502. // Destructor for UndoLinkedList
  503. //------------------------------------------------------------------------------
  504.  
  505. UndoLinkedList::~UndoLinkedList()
  506. {
  507.     // The list does NOT delete all its links!
  508. }
  509.  
  510. //------------------------------------------------------------------------------
  511. // UndoLinkedList::Remove
  512. //
  513. // Description
  514. //------------------------------------------------------------------------------
  515.  
  516. void    UndoLinkedList::Remove(UndoLink& aLink)
  517. {
  518.     fSeed++;
  519.     aLink.Remove();
  520. }
  521.  
  522. //------------------------------------------------------------------------------
  523. // UndoLinkedList::RemoveFirst
  524. //
  525. // Description
  526. //------------------------------------------------------------------------------
  527.  
  528. UndoLink* UndoLinkedList::RemoveFirst()
  529. {
  530.     UndoLink* old = fSentinel.GetNext();
  531.     if (this->NotSentinel(old))
  532.     {
  533.         fSeed++;
  534.         old->Remove();
  535.         return old;
  536.     }
  537.     else
  538.     {
  539.         return kODNULL;
  540.     }
  541. }
  542.  
  543. //------------------------------------------------------------------------------
  544. // UndoLinkedList::AddFirst
  545. //
  546. // Description
  547. //------------------------------------------------------------------------------
  548.  
  549. void    UndoLinkedList::AddFirst(UndoLink* link)
  550. {
  551.     link->AddAfter(this->GetSentinel());
  552.     fSeed++;
  553. }
  554.  
  555. //------------------------------------------------------------------------------
  556. // UndoLinkedList::First
  557. //
  558. // Description
  559. //------------------------------------------------------------------------------
  560.  
  561. UndoLink*    UndoLinkedList::First()  const
  562. {
  563.     return this->NotSentinel(fSentinel.GetNext()) ? fSentinel.GetNext() : (UndoLink*) kODNULL;
  564. }
  565.  
  566. //======================================================================================
  567. // Class UndoLinkedListIterator
  568. //======================================================================================
  569.  
  570. //------------------------------------------------------------------------------
  571. // UndoLinkedListIterator::UndoLinkedListIterator
  572. //
  573. // Constructor for UndoLinkedListIterator
  574. //------------------------------------------------------------------------------
  575.  
  576. UndoLinkedListIterator::UndoLinkedListIterator(UndoLinkedList* list)
  577. {
  578.     fList = list;
  579.     fCurrent = kODNULL;
  580.     fNext = kODNULL;
  581.     fPrevious = kODNULL;
  582.     fSentinel = &list->fSentinel;
  583.     fSeed = fList->fSeed;    
  584. }
  585.  
  586. //------------------------------------------------------------------------------
  587. // UndoLinkedListIterator::~UndoLinkedListIterator
  588. //
  589. // Destructor for UndoLinkedListIterator
  590. //------------------------------------------------------------------------------
  591.  
  592. UndoLinkedListIterator::~UndoLinkedListIterator()
  593. {
  594. }
  595.  
  596. //------------------------------------------------------------------------------
  597. // UndoLinkedListIterator::First
  598. //
  599. // Description
  600. //------------------------------------------------------------------------------
  601.  
  602. UndoLink* UndoLinkedListIterator::First()
  603. {
  604.     if (fList == kODNULL)
  605.         return kODNULL;
  606.         
  607.     if (fSeed != fList->fSeed)
  608.         THROW(kODErrIteratorOutOfSync);
  609.         
  610.     fCurrent = fList->First();
  611.     if (fCurrent == fSentinel)
  612.         fCurrent = kODNULL;
  613.     return fCurrent;
  614. }
  615.  
  616. //------------------------------------------------------------------------------
  617. // UndoLinkedListIterator::Next
  618. //
  619. // Description
  620. //------------------------------------------------------------------------------
  621.  
  622. UndoLink* UndoLinkedListIterator::Next()
  623. {
  624.     if (fList == kODNULL)
  625.         return kODNULL;
  626.  
  627.     if (fSeed != fList->fSeed)
  628.         THROW(kODErrIteratorOutOfSync);
  629.  
  630.     if (fCurrent == kODNULL)
  631.     {
  632.         if ((fNext == kODNULL) && (fPrevious == kODNULL))    // Just starting out
  633.         {
  634.             return this->First();
  635.         }
  636.         else    // Just deleted
  637.         {
  638.             fCurrent = fNext;
  639.             fPrevious = kODNULL;
  640.             fNext = kODNULL;
  641.         }
  642.     }
  643.     else
  644.         fCurrent = fCurrent->GetNext();
  645.     
  646.     if (fCurrent == fSentinel)
  647.         fCurrent = kODNULL;
  648.     return fCurrent;
  649. }
  650.  
  651. //------------------------------------------------------------------------------
  652. // UndoLinkedListIterator::IsNotComplete
  653. //
  654. // Description
  655. //------------------------------------------------------------------------------
  656.  
  657. ODBoolean UndoLinkedListIterator::IsNotComplete()
  658. {
  659.     return (fCurrent != kODNULL);
  660. }
  661.  
  662. //======================================================================================
  663. // Class UndoValueLink - Implementation
  664. //======================================================================================
  665.  
  666. UndoValueLink::UndoValueLink(ElementType value)
  667. {
  668.     fValue = value;
  669. }
  670.  
  671. UndoValueLink::~UndoValueLink()
  672. {
  673. }
  674.  
  675. //======================================================================================
  676. // Class UndoOrderedCollection
  677. //======================================================================================
  678.  
  679. //------------------------------------------------------------------------------
  680. // UndoOrderedCollection::UndoOrderedCollection
  681. //------------------------------------------------------------------------------
  682.  
  683. UndoOrderedCollection::UndoOrderedCollection()
  684. {
  685.     fHeap = kODSystemHeap;
  686. }
  687.  
  688. //------------------------------------------------------------------------------
  689. // UndoOrderedCollection::UndoOrderedCollection
  690. //------------------------------------------------------------------------------
  691.  
  692. UndoOrderedCollection::UndoOrderedCollection(ODUndoMemoryAllocation where)
  693. {
  694.     fHeap = where;
  695. }
  696.  
  697. // UndoOrderedCollection::~UndoOrderedCollection
  698. //------------------------------------------------------------------------------
  699.  
  700. UndoOrderedCollection::~UndoOrderedCollection()
  701. {
  702.     this->RemoveAll();
  703. }
  704.  
  705. //------------------------------------------------------------------------------
  706. // UndoOrderedCollection::AddFirst
  707. //------------------------------------------------------------------------------
  708.  
  709. void UndoOrderedCollection::AddFirst(ElementType element)
  710. {
  711.     UndoValueLink* newLink = this->CreateNewLink(element);
  712.     fImplementation.AddFirst(newLink);
  713. }
  714.  
  715. //------------------------------------------------------------------------------
  716. // UndoOrderedCollection::First
  717. //------------------------------------------------------------------------------
  718.  
  719. ElementType UndoOrderedCollection::First()
  720. {
  721.     UndoValueLink* firstLink = (UndoValueLink*) fImplementation.First();
  722.     return firstLink ? firstLink->GetValue() : (ElementType)kODNULL;
  723. }
  724.  
  725. //------------------------------------------------------------------------------
  726. // UndoOrderedCollection::RemoveFirst
  727. //------------------------------------------------------------------------------
  728.  
  729. ElementType    UndoOrderedCollection::RemoveFirst()
  730. {
  731.     UndoValueLink* aLink = (UndoValueLink*) fImplementation.RemoveFirst();
  732.     ElementType value = aLink ? aLink->GetValue() : kODNULL;
  733.     delete aLink;
  734.     return value;
  735. }
  736.  
  737. //------------------------------------------------------------------------------
  738. // UndoOrderedCollection::Remove
  739. //------------------------------------------------------------------------------
  740.  
  741. void UndoOrderedCollection::Remove(ElementType existing)
  742. {
  743.     UndoLinkedListIterator iter(&fImplementation);
  744.     UndoValueLink* aLink = (UndoValueLink*) iter.First();
  745.     while (aLink != kODNULL)
  746.     {
  747.         ElementType v = ((UndoValueLink*) aLink)->GetValue();
  748.  
  749.         if (this->ElementsMatch(v,existing))
  750.         {
  751.             fImplementation.Remove(*aLink);
  752.             delete aLink;
  753.             aLink = kODNULL;    
  754.         }
  755.         else
  756.             aLink = (UndoValueLink*) iter.Next();
  757.     }    
  758. }
  759.  
  760. //------------------------------------------------------------------------------
  761. // UndoOrderedCollection::RemoveAll
  762. //------------------------------------------------------------------------------
  763.  
  764. void UndoOrderedCollection::RemoveAll()
  765. {
  766.     UndoLink* link = fImplementation.RemoveFirst();
  767.     while (link != kODNULL)
  768.     {
  769.         delete link;
  770.         link = fImplementation.RemoveFirst();
  771.     }
  772. }
  773.  
  774. //------------------------------------------------------------------------------
  775. // UndoOrderedCollection::CreateNewLink
  776. //------------------------------------------------------------------------------
  777.  
  778. UndoValueLink*    UndoOrderedCollection::CreateNewLink(ElementType value) const
  779. {
  780.     return new (fHeap) UndoValueLink(value);
  781. }
  782.  
  783. //------------------------------------------------------------------------------
  784. // UndoOrderedCollection::ElementsMatch
  785. //------------------------------------------------------------------------------
  786.  
  787. ODBoolean    UndoOrderedCollection::ElementsMatch(ElementType v1,ElementType v2) const
  788. {
  789.     return (v1 == v2);
  790. }
  791.  
  792. //======================================================================================
  793. // UndoOrderedCollectionIterator
  794. //======================================================================================
  795.  
  796. //------------------------------------------------------------------------------
  797. // UndoOrderedCollectionIterator::UndoOrderedCollectionIterator
  798. //------------------------------------------------------------------------------
  799.  
  800. UndoOrderedCollectionIterator::UndoOrderedCollectionIterator(UndoOrderedCollection* collection)    
  801.     : fImplementation(collection ? &(collection->fImplementation) : (UndoLinkedList*)kODNULL)
  802. {
  803.     fCollection =  collection;
  804. }
  805.  
  806. //------------------------------------------------------------------------------
  807. // UndoOrderedCollectionIterator::~UndoOrderedCollectionIterator
  808. //------------------------------------------------------------------------------
  809.  
  810. UndoOrderedCollectionIterator::~UndoOrderedCollectionIterator()                        
  811. {
  812. }
  813.  
  814. //------------------------------------------------------------------------------
  815. // UndoOrderedCollectionIterator::First
  816. //------------------------------------------------------------------------------
  817.  
  818. ElementType    UndoOrderedCollectionIterator::First()
  819. {
  820.     UndoValueLink* link = (UndoValueLink*) fImplementation.First();
  821.     
  822.     return link ? link->GetValue() : (ElementType)kODNULL;
  823. }
  824.  
  825. //------------------------------------------------------------------------------
  826. // UndoOrderedCollectionIterator::Next
  827. //------------------------------------------------------------------------------
  828.  
  829. ElementType    UndoOrderedCollectionIterator::Next()
  830. {        
  831.     UndoValueLink* link = (UndoValueLink*) fImplementation.Next();
  832.     
  833.     return link ? link->GetValue() : (ElementType)kODNULL;
  834. }
  835.  
  836. //------------------------------------------------------------------------------
  837. // UndoOrderedCollectionIterator::IsNotComplete
  838. //------------------------------------------------------------------------------
  839.  
  840. ODBoolean    UndoOrderedCollectionIterator::IsNotComplete()
  841. {
  842.     return fImplementation.IsNotComplete();
  843. }
  844.  
  845.  
  846.  
  847. /////////////// END TEMP HACK
  848.  
  849.  
  850.  
  851. //==============================================================================
  852. // Constants
  853. //==============================================================================
  854.  
  855. const OSType kUndoNotifyID = 'undo';
  856. const OSType kRedoNotifyID = 'redo';
  857. const OSType kDisposeActionNotifyID = 'del ';
  858.  
  859. const AEKeyword kDataPtrKeyword = 'data';
  860. const AEKeyword kPartPtrKeyword = 'part';
  861. const AEKeyword kDoneStateKeyword = 'done';
  862.  
  863. // A number of functions can share code. They pass along this enum to know
  864. //    which course of action to take.
  865. enum ODUndoRedoType
  866. {
  867.     kUndo,
  868.     kRedo,
  869.     kDispose
  870. };
  871.  
  872. //==============================================================================
  873. // Classes used in this file
  874. //==============================================================================
  875.  
  876. class UndoAction;
  877. class SystemUndo;
  878.  
  879. //==============================================================================
  880. // Function Prototypes
  881. //==============================================================================
  882.  
  883. const ODBoolean kODBringToFront = kODTrue;
  884.  
  885. static OSErr NotifyUndoOrRedoOrDispose(UndoAction* action,
  886.                                                 ODUndoRedoType which,
  887.                                                 ODBoolean bringToFront);
  888. static OSErr NotifyUndo(UndoAction* action, ODBoolean bringToFront);
  889. static OSErr NotifyRedo(UndoAction* action, ODBoolean bringToFront);
  890. static OSErr NotifyDispose(UndoAction* action);
  891. static SystemUndo *GetSystemUndo();
  892. static ODBoolean SetSystemUndo(SystemUndo *systemUndo);
  893.  
  894. //==============================================================================
  895. // Functions
  896. //==============================================================================
  897.  
  898. // • Using ASLM we registered the system undo object with ASLM using the
  899. // arbitration mechanism provided by ASLM. To eliminate our dependency on ASLM
  900. // we are storing the system undo object in a global which is accessed by the
  901. // following two functions. This is NOT a thread safe method for accessing the
  902. // system undo!
  903.  
  904. //------------------------------------------------------------------------------
  905. // GetSystemUndo
  906. //------------------------------------------------------------------------------
  907.  
  908. #pragma lib_export on
  909. extern SystemUndo* gSystemUndo;        
  910. #pragma lib_export off
  911.  
  912. static SystemUndo *GetSystemUndo()
  913. {
  914.     return gSystemUndo;
  915. }
  916.  
  917. //------------------------------------------------------------------------------
  918. // SetSystemUndo
  919. //------------------------------------------------------------------------------
  920.  
  921. static ODBoolean SetSystemUndo(SystemUndo *systemUndo)
  922. {
  923.     gSystemUndo = systemUndo;
  924.     return kODTrue;
  925. }
  926.  
  927. //#pragma lib_export off
  928.  
  929. //==============================================================================
  930. // Local Classes
  931. //==============================================================================
  932.  
  933. //------------------------------------------------------------------------------
  934.  
  935. class UndoAction
  936. {
  937.   public:
  938.         void operator delete(void* ptr) {DisposePtr((Ptr)ptr);}
  939.     UndoAction(ODPart* whichPart, ODActionData* actionData,
  940.                     ODActionType actionType, ODName* undoActionLabel,
  941.                     ODName* redoActionLabel);
  942.     ~UndoAction();
  943.  
  944.     ODPart*                fPart;
  945.     ProcessSerialNumber    fProcessNum;
  946.     ODActionData*        fActionData;
  947.     ODActionType        fActionType;
  948.     ODName*                fUndoActionLabel;
  949.     ODName*                fRedoActionLabel;
  950.     ODBoolean            fMark;
  951.     ODDoneState            fDoneState;
  952. };
  953.  
  954. //------------------------------------------------------------------------------
  955. // UndoAction::UndoAction
  956. //
  957. //    This constructor may throw an error, but it's OK because there is nothing
  958. //    to deallocate in the destructor.
  959. //------------------------------------------------------------------------------
  960.  
  961. UndoAction::UndoAction(ODPart* whichPart, 
  962.                                     ODActionData* actionData,
  963.                                     ODActionType actionType,
  964.                                     ODName* undoActionLabel,
  965.                                     ODName* redoActionLabel)
  966. {
  967.     fPart = whichPart;
  968.     THROW_IF_ERROR(GetCurrentProcess(&fProcessNum));
  969.     fActionData = actionData;
  970.     fActionType = actionType;
  971.     fUndoActionLabel = undoActionLabel;
  972.     fRedoActionLabel = redoActionLabel;
  973.     fMark = kODFalse;
  974.     fDoneState = kODDone;
  975. }
  976.  
  977. //------------------------------------------------------------------------------
  978. // UndoAction::~UndoAction
  979. //
  980. //    Notify owning part owning fActionData to dipose of any associated memory.
  981. //------------------------------------------------------------------------------
  982.  
  983. UndoAction::~UndoAction()
  984. {
  985.     // Note that we may leak memory if NotifyDispose returns anything other than
  986.     // noErr. However, it is possible that the process allocating the memory for 
  987.     // the undo action no longer exists. That's why we are trying to avoid allocation.
  988.  
  989.     if (NotifyDispose(this) != procNotFound)
  990.     {
  991.         TRY
  992.             if (fUndoActionLabel)
  993.                 DisposeIText(fUndoActionLabel);
  994.             if (fRedoActionLabel)
  995.                 DisposeIText(fRedoActionLabel);
  996.             if (fActionData)
  997.                 DisposeByteArray(fActionData);
  998.         CATCH_ALL
  999.             WARN("Error %ld encountered deleting an undo action.", ErrorCode());
  1000.         ENDTRY
  1001.     }
  1002. }
  1003.  
  1004. //------------------------------------------------------------------------------
  1005.  
  1006. class SystemUndo
  1007. {
  1008.   public:
  1009.         void operator delete(void* ptr) {DisposePtr((Ptr)ptr);}
  1010.     SystemUndo();
  1011.     ~SystemUndo();
  1012.     void    Initialize();
  1013.  
  1014.     ODSize        Purge(ODSize size);
  1015.     ODBoolean    CheckActionOK(UndoAction* action);
  1016.     void        AddActionToHistory(ODPart* whichPart, 
  1017.                                     ODActionData* actionData,
  1018.                                     ODActionType actionType,
  1019.                                     ODName* undoActionLabel,
  1020.                                     ODName* redoActionLabel);
  1021.     void    Undo();
  1022.     void    Redo();
  1023.     void    MarkActionHistory();
  1024.     void    ClearActionHistory(ODRespectMarksChoices respectMarks);
  1025.     void    ClearRedoHistory();
  1026.     ODBoolean    PeekUndoHistory(ODPart** part,
  1027.                                 ODActionData* actionData,
  1028.                                 ODActionType* actionType,
  1029.                                 ODName* actionLabel);
  1030.     ODBoolean    PeekRedoHistory(ODPart** part,
  1031.                                 ODActionData* actionData,
  1032.                                 ODActionType* actionType,
  1033.                                 ODName* actionLabel);
  1034.     void        RemoveEntriesForThisProcess();
  1035.     void        AddClient(ODUndo* docUndoObject);
  1036.     void        RemoveClient(ODUndo* docUndoObject);
  1037.     ODULong        GetNumClients();
  1038.     void        AbortCurrentTransaction();
  1039.   private:
  1040.     void        TransactionUndo(UndoAction* firstAction);
  1041.     void        TransactionRedo(UndoAction* firstAction);
  1042.     void        MarkActionOrSelf(UndoAction* action, ODBoolean* mark);
  1043.     void        ClearActionsToMark(UndoOrderedCollection* stack);
  1044.     void        ClearStack(UndoOrderedCollection* stack);
  1045.     ODBoolean    PeekHistory(ODPart** part,
  1046.                                 ODActionData* actionData,
  1047.                                 ODActionType* actionType,
  1048.                                 ODName* actionLabel,
  1049.                                 ODUndoRedoType which);
  1050.     void        MoveUndoToRedo();
  1051.     void        MoveRedoToUndo();
  1052.     ODBoolean     ShouldStackBeCleared(UndoOrderedCollection* stack);
  1053.     
  1054.     UndoOrderedCollection*        fUndoStack;
  1055.     UndoOrderedCollection*        fRedoStack;
  1056.     ODULong                        fInTransaction;
  1057.     ODBoolean                fCurrentlyUndoingOrRedoing;
  1058.     ODULong                fNumUsers;
  1059. };
  1060.  
  1061. //------------------------------------------------------------------------------
  1062. // SystemUndo::SystemUndo
  1063. //------------------------------------------------------------------------------
  1064.  
  1065. SystemUndo::SystemUndo()
  1066. {
  1067.     fUndoStack = kODNULL;
  1068.     fRedoStack = kODNULL;
  1069.     fInTransaction = 0;
  1070.     fCurrentlyUndoingOrRedoing = kODFalse;
  1071.     fNumUsers = 0;
  1072. }
  1073.  
  1074. //------------------------------------------------------------------------------
  1075. // SystemUndo::Initialize                
  1076. //------------------------------------------------------------------------------
  1077.  
  1078. void SystemUndo::Initialize ()
  1079. {
  1080.     ODUndoMemoryAllocation    heap = kODSystemHeap;
  1081.  
  1082.     fUndoStack = new (heap) UndoOrderedCollection(heap);
  1083.     fRedoStack = new (heap) UndoOrderedCollection(heap);
  1084.  
  1085. }
  1086.  
  1087. //------------------------------------------------------------------------------
  1088. // SystemUndo::~SystemUndo
  1089. //------------------------------------------------------------------------------
  1090.  
  1091. SystemUndo::~SystemUndo()
  1092. {
  1093. //    WASSERTM(0, "System Undo object being destroyed!");
  1094.     delete fUndoStack;
  1095.     delete fRedoStack;
  1096. }
  1097.  
  1098. //------------------------------------------------------------------------------
  1099. // SystemUndo::Purge
  1100. //------------------------------------------------------------------------------
  1101.         
  1102. ODSize    SystemUndo::Purge(ODSize size)
  1103. {
  1104.     ODUnused(size);
  1105.     return 0;
  1106. }
  1107.  
  1108. //------------------------------------------------------------------------------
  1109. // SystemUndo::CheckActionOK
  1110. //------------------------------------------------------------------------------
  1111.         
  1112. ODBoolean SystemUndo::CheckActionOK(UndoAction* action)
  1113. {
  1114.     if (action && !(action->fMark))
  1115.         return kODTrue;
  1116.     return kODFalse;
  1117. }
  1118.  
  1119. //------------------------------------------------------------------------------
  1120. // SystemUndo::AddClient
  1121. //------------------------------------------------------------------------------
  1122.         
  1123. void SystemUndo::AddClient(ODUndo* docUndoObject)
  1124. {
  1125.     ODUnused(docUndoObject);
  1126.     ++fNumUsers;
  1127. }
  1128.  
  1129. //------------------------------------------------------------------------------
  1130. // SystemUndo::RemoveClient
  1131. //------------------------------------------------------------------------------
  1132.         
  1133. void SystemUndo::RemoveClient(ODUndo* docUndoObject)
  1134. {
  1135.     ODUnused(docUndoObject);
  1136.     --fNumUsers;
  1137. }
  1138.  
  1139. //------------------------------------------------------------------------------
  1140. // SystemUndo::GetNumClients
  1141. //------------------------------------------------------------------------------
  1142.         
  1143. ODULong SystemUndo::GetNumClients()
  1144. {
  1145.     return fNumUsers;
  1146. }
  1147.  
  1148. //------------------------------------------------------------------------------
  1149. // SystemUndo::AddActionToHistory
  1150. //------------------------------------------------------------------------------
  1151.  
  1152. void SystemUndo::AddActionToHistory(ODPart* whichPart, 
  1153.                                     ODActionData* actionData,
  1154.                                     ODActionType actionType,
  1155.                                     ODName* undoActionLabel,
  1156.                                     ODName* redoActionLabel)
  1157. {
  1158.     if (fCurrentlyUndoingOrRedoing)
  1159.         THROW(kODErrCannotAddAction);
  1160.  
  1161. //    if (fInTransaction && actionType == kODBeginAction)
  1162. //        THROW(kODErrCannotAddAction);
  1163.  
  1164.     if (actionType == kODBeginAction)
  1165.         ++fInTransaction;
  1166.     if (actionType == kODEndAction)
  1167.         --fInTransaction;
  1168.  
  1169.     // NOT DOING THESE ALLOCATIONS IN THE SYSTEM HEAP!
  1170. //    if (undoActionLabel)
  1171.         ODIText* undoName = CopyIText(undoActionLabel);
  1172. //    if (redoActionLabel)
  1173.         ODIText* redoName = CopyIText(redoActionLabel);
  1174.  
  1175. //    if (actionData)
  1176.         ODActionData* copiedData = CopyByteArray(actionData);
  1177.  
  1178.     UndoAction* action =
  1179.                     new (kODSystemHeap) UndoAction(whichPart, copiedData,
  1180.                                                     actionType, undoName,
  1181.                                                     redoName);
  1182.     fUndoStack->AddFirst(action);
  1183.     this->ClearStack(fRedoStack);
  1184. }
  1185.  
  1186. //------------------------------------------------------------------------------
  1187. // SystemUndo::MoveUndoToRedo
  1188. //
  1189. //    Utility to move item from top of one stack to the top of another.
  1190. //------------------------------------------------------------------------------
  1191.  
  1192. void SystemUndo::MoveUndoToRedo()
  1193. {
  1194.     ElementType item = fUndoStack->RemoveFirst();
  1195.     ((UndoAction*)item)->fDoneState = kODUndone;
  1196.     fRedoStack->AddFirst(item);
  1197. }
  1198.  
  1199. //------------------------------------------------------------------------------
  1200. // SystemUndo::MoveRedoToUndo
  1201. //
  1202. //    Utility to move item from top of one stack to the top of another.
  1203. //------------------------------------------------------------------------------
  1204.  
  1205. void SystemUndo::MoveRedoToUndo()
  1206. {
  1207.     ElementType item = fRedoStack->RemoveFirst();
  1208.     ((UndoAction*)item)->fDoneState = kODRedone;
  1209.     fUndoStack->AddFirst(item);
  1210. }
  1211.  
  1212. //------------------------------------------------------------------------------
  1213. // SystemUndo::Undo
  1214. //
  1215. //    If there's an error while undoing anything, just clear the stacks and get
  1216. //    out.
  1217. //------------------------------------------------------------------------------
  1218.  
  1219. void SystemUndo::Undo()
  1220. {
  1221.     UndoAction* action = (UndoAction*)fUndoStack->First();
  1222.     if (!this->CheckActionOK(action))
  1223.         THROW(kODErrEmptyStack);
  1224.  
  1225.     fCurrentlyUndoingOrRedoing = kODTrue;
  1226.  
  1227.     TRY
  1228.         if (action->fActionType == kODEndAction) // End is at top for an Undo
  1229.             this->TransactionUndo(action);
  1230.         else
  1231.         {
  1232.             THROW_IF_ERROR(NotifyUndo(action, kODBringToFront));
  1233.             this->MoveUndoToRedo();
  1234.         }
  1235.     CATCH_ALL
  1236.         this->ClearActionHistory(kODDontRespectMarks);
  1237.         fCurrentlyUndoingOrRedoing = kODFalse;
  1238.         RERAISE;
  1239.     ENDTRY
  1240.     fCurrentlyUndoingOrRedoing = kODFalse;
  1241. }
  1242.  
  1243. //------------------------------------------------------------------------------
  1244. // SystemUndo::ShouldStackBeCleared
  1245. //------------------------------------------------------------------------------
  1246.  
  1247. ODBoolean SystemUndo::ShouldStackBeCleared(UndoOrderedCollection* stack)
  1248. {    
  1249.     UndoOrderedCollectionIterator iter(stack);
  1250.     UndoAction* action = (UndoAction*) iter.First();
  1251.     ODULong        nestedTransactionCounter = 0;
  1252.     
  1253.     if (action)
  1254.     {
  1255.         do
  1256.         {
  1257.             if (IsValidProcess(&action->fProcessNum))
  1258.             {
  1259.                 if (action->fActionType == kODBeginAction)
  1260.                     --nestedTransactionCounter;
  1261.                 else if (action->fActionType == kODEndAction)
  1262.                     ++nestedTransactionCounter;
  1263.             }
  1264.             else            
  1265.                 return kODTrue;
  1266.             action = (UndoAction*)iter.Next();
  1267.         }
  1268.         while ((nestedTransactionCounter) && action);
  1269.     }
  1270.     
  1271.     if (nestedTransactionCounter)
  1272.         return kODTrue;
  1273.         
  1274.     return kODFalse;
  1275. }
  1276.  
  1277. //------------------------------------------------------------------------------
  1278. // SystemUndo::TransactionUndo
  1279. //------------------------------------------------------------------------------
  1280.  
  1281. void SystemUndo::TransactionUndo(UndoAction* firstAction)
  1282. {
  1283.     UndoAction*    action;
  1284.     ODULong        nestedTransactionCounter = 1;
  1285.  
  1286.     THROW_IF_ERROR(NotifyUndo(firstAction, ! kODBringToFront));
  1287.     this->MoveUndoToRedo();
  1288.  
  1289.     do
  1290.     {
  1291.         action = (UndoAction*)fUndoStack->First();
  1292.         if (action == (UndoAction*)kODNULL)
  1293.             THROW(kODErrNoBeginAction);
  1294.         THROW_IF_ERROR(NotifyUndo(action, ! kODBringToFront));
  1295.         this->MoveUndoToRedo();
  1296.         if (action->fActionType == kODBeginAction)
  1297.             --nestedTransactionCounter;
  1298.         else if (action->fActionType == kODEndAction)
  1299.             ++nestedTransactionCounter;
  1300.     }
  1301.     while (nestedTransactionCounter);
  1302. }
  1303.  
  1304. //------------------------------------------------------------------------------
  1305. // SystemUndo::Redo
  1306. //------------------------------------------------------------------------------
  1307.  
  1308. void SystemUndo::Redo()
  1309. {
  1310.     UndoAction* action = (UndoAction*)fRedoStack->First();
  1311.     if (!this->CheckActionOK(action))
  1312.         THROW(kODErrEmptyStack);
  1313.  
  1314.     fCurrentlyUndoingOrRedoing = kODTrue;
  1315.  
  1316.     TRY
  1317.         if (action->fActionType == kODBeginAction)//Start is at top for an Redo
  1318.             this->TransactionRedo(action);
  1319.         else
  1320.         {
  1321.             THROW_IF_ERROR(NotifyRedo(action, kODBringToFront));
  1322.             this->MoveRedoToUndo();
  1323.         }
  1324.     CATCH_ALL
  1325.         this->ClearActionHistory(kODDontRespectMarks);
  1326.         fCurrentlyUndoingOrRedoing = kODFalse;
  1327.         RERAISE;
  1328.     ENDTRY
  1329.     fCurrentlyUndoingOrRedoing = kODFalse;
  1330. }
  1331.  
  1332. //------------------------------------------------------------------------------
  1333. // SystemUndo::TransactionRedo
  1334. //------------------------------------------------------------------------------
  1335.  
  1336. void SystemUndo::TransactionRedo(UndoAction* firstAction)
  1337. {
  1338.     UndoAction*    action;
  1339.     ODULong        nestedTransactionCounter = 1;
  1340.  
  1341.     THROW_IF_ERROR(NotifyRedo(firstAction, ! kODBringToFront));
  1342.     this->MoveRedoToUndo();
  1343.  
  1344.     do
  1345.     {
  1346.         action = (UndoAction*)fRedoStack->First();
  1347. //        if (action == (UndoAction*)kODNULL)
  1348. //            THROW(kODErrNoBeginAction);
  1349.         THROW_IF_ERROR(NotifyRedo(action, ! kODBringToFront));
  1350.         this->MoveRedoToUndo();
  1351.         if (action->fActionType == kODBeginAction)
  1352.             ++nestedTransactionCounter;
  1353.         else if (action->fActionType == kODEndAction)
  1354.             --nestedTransactionCounter;
  1355.     }
  1356.     while (nestedTransactionCounter);
  1357. }
  1358.  
  1359. //------------------------------------------------------------------------------
  1360. // SystemUndo::MarkActionHistory
  1361. //------------------------------------------------------------------------------
  1362.  
  1363. void SystemUndo::MarkActionHistory()
  1364. {
  1365.     UndoAction*    action;
  1366.  
  1367.     action = (UndoAction*)fUndoStack->First();
  1368.     if (action)
  1369.         action->fMark = kODTrue;
  1370.     action = (UndoAction*)fRedoStack->First();
  1371.     if (action)
  1372.         action->fMark = kODTrue;
  1373. }
  1374.  
  1375. //------------------------------------------------------------------------------
  1376. // SystemUndo::ClearStack
  1377. //------------------------------------------------------------------------------
  1378.  
  1379. void SystemUndo::ClearStack(UndoOrderedCollection* stack)
  1380. {
  1381.     UndoOrderedCollectionIterator    iter(stack);
  1382.     UndoAction*            action;
  1383.  
  1384.     for (action = (UndoAction*)iter.First();
  1385.             iter.IsNotComplete();
  1386.             action = (UndoAction*)iter.Next())
  1387.     {
  1388.         delete action;
  1389.     }
  1390.     
  1391.     stack->RemoveAll();
  1392. }
  1393.  
  1394. //------------------------------------------------------------------------------
  1395. // SystemUndo::ClearActionsToMark
  1396. //
  1397. //    To make more efficient, should just start removing items from the front of
  1398. //    the list til I hit the mark.
  1399. //------------------------------------------------------------------------------
  1400.  
  1401. void SystemUndo::ClearActionsToMark(UndoOrderedCollection* stack)
  1402. {
  1403.     UndoOrderedCollectionIterator    collectionIter(stack);
  1404.     UndoAction*                    action;
  1405.     UndoOrderedCollection            elementsToDelete;
  1406.  
  1407.     // ADD ELEMENTS TO REMOVE TO A LIST
  1408.     for (action = (UndoAction*)collectionIter.First();
  1409.             collectionIter.IsNotComplete();
  1410.             action = (UndoAction*)collectionIter.Next())
  1411.     {
  1412.         if (action->fMark != kODFalse)
  1413.         {
  1414.             action->fMark = kODFalse;
  1415.             break;
  1416.         }
  1417.         else
  1418.             elementsToDelete.AddFirst(action);
  1419.     }
  1420.  
  1421.     // REMOVE ELEMENTS
  1422.     UndoOrderedCollectionIterator    deleteIter(&elementsToDelete);
  1423.     for (action = (UndoAction*)deleteIter.First();
  1424.             deleteIter.IsNotComplete();
  1425.             action = (UndoAction*)deleteIter.Next())
  1426.     {
  1427.         stack->Remove(action);
  1428.         delete action;
  1429.     }
  1430. }
  1431.  
  1432. //------------------------------------------------------------------------------
  1433. // SystemUndo::ClearActionHistory
  1434. //------------------------------------------------------------------------------
  1435.  
  1436. void SystemUndo::ClearActionHistory(ODRespectMarksChoices respectMarks)
  1437. {
  1438.     if (respectMarks == kODRespectMarks)
  1439.     {
  1440.         this->ClearActionsToMark(fUndoStack);
  1441.         this->ClearActionsToMark(fRedoStack);
  1442.     }
  1443.     else
  1444.     {
  1445.         this->ClearStack(fUndoStack);
  1446.         this->ClearStack(fRedoStack);
  1447.     }
  1448. }
  1449.  
  1450. //------------------------------------------------------------------------------
  1451. // SystemUndo::ClearRedoHistory
  1452. //------------------------------------------------------------------------------
  1453.  
  1454. void SystemUndo::ClearRedoHistory()
  1455. {
  1456.     this->ClearActionsToMark(fRedoStack);
  1457. }
  1458.  
  1459. //------------------------------------------------------------------------------
  1460. // SystemUndo::AbortCurrentTransaction
  1461. //------------------------------------------------------------------------------
  1462.  
  1463. void SystemUndo::AbortCurrentTransaction()
  1464. {
  1465.     ODULong            nestingLevel = 0;
  1466.     ODActionType    actionType;
  1467.  
  1468.     if (fCurrentlyUndoingOrRedoing)
  1469.         return;
  1470.     if (!fInTransaction)
  1471.         return;
  1472.     
  1473.     UndoAction* action = (UndoAction*)fUndoStack->First();
  1474.  
  1475.     do
  1476.     {
  1477.         if (action->fActionType == kODEndAction)
  1478.             ++nestingLevel;
  1479.         fUndoStack->RemoveFirst();
  1480.         actionType = action->fActionType;
  1481.         THROW_IF_ERROR(NotifyUndo(action,  ! kODBringToFront));
  1482.         action->fDoneState = kODUndone;
  1483.         delete action;
  1484.         if (actionType == kODBeginAction && nestingLevel == 0)
  1485.             break;
  1486.         action = (UndoAction*)fUndoStack->First();//should never be NULL, right?
  1487.     }
  1488.     while (kODTrue);
  1489. }
  1490.  
  1491. //------------------------------------------------------------------------------
  1492. // SystemUndo::PeekUndoHistory
  1493. //------------------------------------------------------------------------------
  1494.  
  1495. ODBoolean SystemUndo::PeekUndoHistory(ODPart** part,
  1496.                                 ODActionData* actionData,
  1497.                                 ODActionType* actionType,
  1498.                                 ODName* actionLabel)
  1499. {
  1500.     return PeekHistory(part, actionData, actionType, actionLabel, kUndo);
  1501. }
  1502.  
  1503. //------------------------------------------------------------------------------
  1504. // SystemUndo::PeekRedoHistory
  1505. //------------------------------------------------------------------------------
  1506.  
  1507. ODBoolean SystemUndo::PeekRedoHistory(ODPart** part,
  1508.                                 ODActionData* actionData,
  1509.                                 ODActionType* actionType,
  1510.                                 ODName* actionLabel)
  1511. {
  1512.     return PeekHistory(part, actionData, actionType, actionLabel, kRedo);
  1513. }
  1514.  
  1515. //------------------------------------------------------------------------------
  1516. // SystemUndo::PeekHistory
  1517. //
  1518. //    We could choose to only fill out the pieces needed here.
  1519. //------------------------------------------------------------------------------
  1520.  
  1521. ODBoolean SystemUndo::PeekHistory(ODPart** part,
  1522.                                 ODActionData* actionData,
  1523.                                 ODActionType* actionType,
  1524.                                 ODName* actionLabel,
  1525.                                 ODUndoRedoType which)
  1526. {
  1527.     UndoOrderedCollection*    stack;
  1528.     ODIText*                iText;
  1529.     ODBoolean                createPhonyIText = kODFalse;
  1530.  
  1531.     if (which == kUndo)
  1532.         stack = fUndoStack;
  1533.     else if (which == kRedo)
  1534.         stack = fRedoStack;
  1535.  
  1536.     UndoAction*    action = (UndoAction*)stack->First();
  1537.  
  1538.     if (!this->CheckActionOK(action))
  1539.         return kODFalse;
  1540.     else
  1541.     {
  1542.         if (action->fMark != kODFalse)
  1543.             return kODFalse;
  1544.         // We need to see whether the action is still valid
  1545.         // (i.e., whether the process is still up and running).
  1546.         else if (this->ShouldStackBeCleared(stack))
  1547.         {
  1548.             this->ClearActionHistory(kODDontRespectMarks);
  1549.             return kODFalse;
  1550.         }
  1551.         else
  1552.         {
  1553.             *part = action->fPart;
  1554.             *actionType = action->fActionType;
  1555.  
  1556.             // NP: null data mods
  1557.             if (action->fActionData)
  1558.                 *actionData = CopyByteArrayStruct(action->fActionData);
  1559.             else
  1560.                 *actionData = CreateEmptyByteArrayStruct(0);
  1561.  
  1562.             if (which == kUndo)
  1563.             {
  1564.                 if (action->fUndoActionLabel)
  1565.                     iText = action->fUndoActionLabel;
  1566.                 else
  1567.                     // NP: null data mods
  1568.                     createPhonyIText = kODTrue;
  1569.             }
  1570.             else if (which == kRedo)
  1571.             {
  1572.                 if (action->fRedoActionLabel)
  1573.                     iText = action->fRedoActionLabel;
  1574.                 else
  1575.                     // NP: null data mods
  1576.                     createPhonyIText = kODTrue;
  1577.             }
  1578.  
  1579.             if (createPhonyIText)
  1580.             {
  1581.                 // NP: null data mods
  1582.                 ODIText*    emptyIText = CreateIText(0);
  1583.                 *actionLabel = CopyITextStruct(emptyIText);
  1584.                 DisposeIText(emptyIText);
  1585.             }
  1586.             else
  1587.                 *actionLabel = CopyITextStruct(iText);
  1588.  
  1589.             return kODTrue;
  1590.         }
  1591.     }
  1592. }
  1593.  
  1594. //------------------------------------------------------------------------------
  1595. // NotifyUndoOrRedoOrDispose
  1596. //
  1597. //    Notify part to Undo or Redo or Dispose its data.
  1598. //    Could fine-tune to only pack parameters needed according to "which"
  1599. //    parameter
  1600. //------------------------------------------------------------------------------
  1601.  
  1602. static OSErr NotifyUndoOrRedoOrDispose(UndoAction* action,
  1603.                                                 ODUndoRedoType which,
  1604.                                                 ODBoolean    bringToFront)
  1605. {
  1606.     AEAddressDesc        address;
  1607.     AppleEvent            message;
  1608.     AppleEvent            reply = NULL_DESCRIPTOR_DEFINITION;
  1609.     OSErr                error = noErr;
  1610.     ProcessSerialNumber    psn;
  1611.     Boolean                isSameProcess;
  1612.     DescType            eventID;
  1613. //    ProcessInfoRec        processRec;
  1614.     octet                validAddrForPhonyData;
  1615.  
  1616.     TRY
  1617. #if 0
  1618.         // MAKE SURE PROCESS IS STILL VALID. USE SIDE EFFECT OF ERROR RETURN
  1619.         //    FROM GetProcessInformation.
  1620.         processRec.processInfoLength = sizeof(ProcessInfoRec);
  1621.         processRec.processName = kODNULL;
  1622.         processRec.processAppSpec = kODNULL;
  1623.         THROW_IF_ERROR(GetProcessInformation(&action->fProcessNum, &processRec));
  1624. #endif /* 0 */
  1625.         // SOME CODE TO HANDLE THE SEND TO SELF CASE WELL. IF WE HAVE A STANDARD
  1626.         //    IDLE PROC TO USE, WE PROBABLY DON'T NEED THIS. (NP-WHAT DID I MEAN
  1627.         //    HERE?)
  1628.         THROW_IF_ERROR(GetCurrentProcess(&psn));
  1629.         THROW_IF_ERROR(SameProcess(&action->fProcessNum, &psn,
  1630.                                     &isSameProcess));
  1631.         if (isSameProcess)
  1632.         {
  1633.             psn.lowLongOfPSN = kCurrentProcess;
  1634.             psn.highLongOfPSN = 0;
  1635.         }
  1636.         else
  1637.             psn = action->fProcessNum;
  1638. #if 0
  1639.         {
  1640.             // MAKE SURE PROCESS IS STILL ALIVE.
  1641.             ODBoolean    processStillExists = kODFalse;
  1642.             
  1643.             while (kODTrue)
  1644.             {
  1645.                 if (GetNextProcess(&psn) != noErr)
  1646.                     break;
  1647.                 THROW_IF_ERROR(SameProcess(&action->fProcessNum, &psn,
  1648.                                             &isSameProcess));
  1649.                 if (isSameProcess)
  1650.                 {
  1651.                     processStillExists = kODTrue;
  1652.                     break;
  1653.                 }
  1654.             }
  1655.             
  1656.             if (!processStillExists)
  1657.                 THROW(procNotFound);
  1658.         }
  1659. #endif /* 0 */
  1660.         THROW_IF_ERROR(AECreateDesc(typeProcessSerialNumber,
  1661.                                     (Ptr)&psn, sizeof(psn), &address));
  1662.  
  1663.         TempAEDesc tempAddress(&address);
  1664.         if (which == kUndo)
  1665.             eventID = kUndoNotifyID;
  1666.         else if (which == kRedo)
  1667.             eventID = kRedoNotifyID;
  1668.         else if (which == kDispose)
  1669.             eventID = kDisposeActionNotifyID;
  1670.  
  1671.         THROW_IF_ERROR(AECreateAppleEvent(kODShellSignature, eventID,
  1672.                         &address, kAutoGenerateReturnID, kAnyTransactionID,
  1673.                         &message));
  1674.         TempAEDesc tempMessage(&message); // DMc make sure it is disposed
  1675.     
  1676.         // NP: null data mods
  1677.         if (!action->fActionData)
  1678.         {
  1679.             action->fActionData->_length = 0;
  1680.             action->fActionData->_buffer = &validAddrForPhonyData;
  1681.         }
  1682.         THROW_IF_ERROR(AEPutParamPtr(&message, kDataPtrKeyword, typeChar,
  1683.                                     action->fActionData->_buffer,
  1684.                                     action->fActionData->_length));
  1685.         
  1686.         THROW_IF_ERROR(AEPutParamPtr(&message, kPartPtrKeyword, typeInteger,
  1687.                                     (Ptr)&action->fPart,
  1688.                                     sizeof(action->fPart)));
  1689.         
  1690.         THROW_IF_ERROR(AEPutParamPtr(&message, kDoneStateKeyword, typeInteger,
  1691.                                     (Ptr)&action->fDoneState,
  1692.                                     sizeof(action->fDoneState)));
  1693.         
  1694.         if (bringToFront)
  1695.             SetFrontProcess(&psn);
  1696.  
  1697.         THROW_IF_ERROR(AESend(&message, &reply,
  1698.                                 (which == kDispose ? kAENoReply : kAEWaitReply)
  1699.                                     + kAECanInteract + kAECanSwitchLayer + kAEDontRecord,
  1700.                                 kAENormalPriority,
  1701.                                 kAEDefaultTimeout,
  1702.                                 (AEIdleUPP)kODNULL, (AEFilterUPP)kODNULL));
  1703.  
  1704.         AEDisposeDesc(&reply); // DMc
  1705.     CATCH_ALL
  1706.         error = ErrorCode();
  1707.     ENDTRY
  1708.     
  1709.     return error;
  1710. }
  1711.  
  1712. //------------------------------------------------------------------------------
  1713. // NotifyUndo
  1714. //
  1715. //    Call ODPart::Undo.
  1716. //------------------------------------------------------------------------------
  1717.  
  1718. static OSErr NotifyUndo(UndoAction* action, ODBoolean bringToFront)
  1719. {
  1720.     return NotifyUndoOrRedoOrDispose(action, kUndo, bringToFront);
  1721. }
  1722.  
  1723. //------------------------------------------------------------------------------
  1724. // NotifyRedo
  1725. //
  1726. //    Call ODPart::Redo.
  1727. //------------------------------------------------------------------------------
  1728.  
  1729. static OSErr NotifyRedo(UndoAction* action, ODBoolean bringToFront)
  1730. {
  1731.     return NotifyUndoOrRedoOrDispose(action, kRedo, bringToFront);
  1732. }
  1733.  
  1734. //------------------------------------------------------------------------------
  1735. // NotifyDispose
  1736. //
  1737. //    Call ODPart::DiposeActionState.
  1738. //------------------------------------------------------------------------------
  1739.  
  1740. static OSErr NotifyDispose(UndoAction* action)
  1741. {
  1742.     return NotifyUndoOrRedoOrDispose(action, kDispose, ! kODBringToFront);
  1743. }
  1744.  
  1745. //==============================================================================
  1746. // ODUndo
  1747. //==============================================================================
  1748.  
  1749. //------------------------------------------------------------------------------
  1750. // HandleUndoOrRedoOrDisposeNotify
  1751. //
  1752. //    Could fine-tune to only unpack parameters needed according to "which"
  1753. //    parameter
  1754. //------------------------------------------------------------------------------
  1755.  
  1756. static OSErr HandleUndoOrRedoOrDisposeNotify(AppleEvent* message,
  1757.                                                 AppleEvent* reply,
  1758.                                                 long refCon,
  1759.                                                 ODUndoRedoType which)
  1760. {
  1761.     ODUnused(reply);
  1762.     ODUnused(refCon);
  1763.  
  1764.     OSErr            error = noErr;
  1765.     DescType        gotType;
  1766. //    ODActionData*    data;
  1767.     ODPart*            part;
  1768.     ODDoneState        doneState;
  1769.     Size            actualSize;
  1770. //    Size            maximumDataSize;
  1771.     Size            maximumPartSize = sizeof(part);
  1772.     Size            maximumDoneStateSize = sizeof(doneState);
  1773.  
  1774.     TRY
  1775. #if 0
  1776.         gotType = typeChar;
  1777.         THROW_IF_ERROR(AESizeOfParam(message, kDataPtrKeyword, &gotType,
  1778.                                         &actualSize));
  1779.         if (gotType != typeChar)
  1780.             THROW(errAECorruptData);
  1781.         maximumDataSize = actualSize;
  1782.         data = CreateEmptyByteArray(actualSize);
  1783.         THROW_IF_ERROR(AEGetParamPtr(message, kDataPtrKeyword, typeChar,
  1784.                                         &gotType, data->_buffer, maximumDataSize,
  1785.                                         &actualSize));
  1786.         if (actualSize != maximumDataSize)
  1787.             THROW(errAECorruptData);
  1788. #endif /* 0 */        
  1789.         TempODByteArray data = ODAEGetByteArray(message, kDataPtrKeyword,
  1790.                                                 typeChar);
  1791.  
  1792.         THROW_IF_ERROR(AEGetParamPtr(message, kPartPtrKeyword, typeInteger,
  1793.                                     &gotType, (Ptr)&part, maximumPartSize,
  1794.                                     &actualSize));
  1795.         if (gotType != typeInteger || actualSize != maximumPartSize)
  1796.             THROW(errAECorruptData);
  1797.         
  1798.         THROW_IF_ERROR(AEGetParamPtr(message, kDoneStateKeyword, typeInteger,
  1799.                                     &gotType, (Ptr)&doneState,
  1800.                                     maximumDoneStateSize,
  1801.                                     &actualSize));
  1802.         if (gotType != typeInteger || actualSize != maximumDoneStateSize)
  1803.             THROW(errAECorruptData);
  1804.         
  1805.         Environment*    ev = somGetGlobalEnvironment();
  1806.         if (which == kUndo)
  1807.         {
  1808.             part->UndoAction(ev, data);
  1809.             error = ODGetSOMException(ev);
  1810.         }
  1811.         else if (which == kRedo)
  1812.         {
  1813.             part->RedoAction(ev, data);
  1814.             error = ODGetSOMException(ev);
  1815.         }
  1816.         else if (which == kDispose)
  1817.         {
  1818.             part->DisposeActionState(ev, data, doneState);
  1819.             error = ODGetSOMException(ev);
  1820.         }
  1821.         
  1822. //        DisposeByteArray(data);
  1823.         
  1824.     CATCH_ALL
  1825.         error = ErrorCode();
  1826.     ENDTRY
  1827.  
  1828.     return error;
  1829. }
  1830.  
  1831. //------------------------------------------------------------------------------
  1832. // HandleUndoNotify                
  1833. //------------------------------------------------------------------------------
  1834.  
  1835. static pascal OSErr HandleUndoNotify(AppleEvent* message, AppleEvent* reply,
  1836.                                         long refCon)
  1837. {
  1838.     return HandleUndoOrRedoOrDisposeNotify(message, reply, refCon, kUndo);
  1839. }
  1840.  
  1841. //------------------------------------------------------------------------------
  1842. // HandleRedoNotify                
  1843. //------------------------------------------------------------------------------
  1844.  
  1845. static pascal OSErr HandleRedoNotify(AppleEvent* message, AppleEvent* reply,
  1846.                                         long refCon)
  1847. {
  1848.     return HandleUndoOrRedoOrDisposeNotify(message, reply, refCon, kRedo);
  1849. }
  1850.  
  1851. //------------------------------------------------------------------------------
  1852. // HandleDisposeNotify                
  1853. //------------------------------------------------------------------------------
  1854.  
  1855. static pascal OSErr HandleDisposeNotify(AppleEvent* message, AppleEvent* reply,
  1856.                                         long refCon)
  1857. {
  1858.     return HandleUndoOrRedoOrDisposeNotify(message, reply, refCon, kDispose);
  1859. }
  1860.  
  1861. //------------------------------------------------------------------------------
  1862. // ODUndo::InitUndo
  1863. //------------------------------------------------------------------------------
  1864.  
  1865. SOM_Scope void  SOMLINK ODUndoInitUndo(ODUndo *somSelf, Environment *ev)
  1866. {
  1867.     ODUndoData *somThis = ODUndoGetData(somSelf);
  1868.     ODUndoMethodDebug("ODUndo","ODUndoInitUndo");
  1869.  
  1870.     /* Moved from somInit. SOM itself sets fields to zero
  1871.     _fSystemUndo = kODNULL;
  1872.     */
  1873.  
  1874.     TRY
  1875.         somSelf->InitObject(ev);
  1876.  
  1877.         _fSystemUndo = GetSystemUndo();
  1878.         if (!_fSystemUndo)
  1879.         {
  1880.             _fSystemUndo = new (kODSystemHeap) SystemUndo();
  1881.             if (_fSystemUndo)
  1882.             {
  1883.                 _fSystemUndo->Initialize();
  1884.                 SetSystemUndo(_fSystemUndo);
  1885.             }
  1886.         }
  1887.         THROW_IF_ERROR(AEInstallEventHandler(kODShellSignature,
  1888.                                     kUndoNotifyID,
  1889.                                     NewAEEventHandlerProc(HandleUndoNotify),
  1890.                                     (long)somSelf, !kIsSysHandler));
  1891.         THROW_IF_ERROR(AEInstallEventHandler(kODShellSignature,
  1892.                                     kRedoNotifyID,
  1893.                                     NewAEEventHandlerProc(HandleRedoNotify),
  1894.                                     (long)somSelf, !kIsSysHandler));
  1895.         THROW_IF_ERROR(AEInstallEventHandler(kODShellSignature,
  1896.                                     kDisposeActionNotifyID,
  1897.                                     NewAEEventHandlerProc(HandleDisposeNotify),
  1898.                                     (long)somSelf, !kIsSysHandler));
  1899.         _fSystemUndo->AddClient(somSelf);
  1900.     CATCH_ALL
  1901.         ODDeleteObject(_fSystemUndo);
  1902.         ODSetSOMException(ev, ErrorCode());
  1903.     ENDTRY
  1904. }
  1905.  
  1906. //------------------------------------------------------------------------------
  1907. // ODUndo::~ODUndo
  1908. //------------------------------------------------------------------------------
  1909.  
  1910. SOM_Scope void  SOMLINK ODUndosomUninit(ODUndo *somSelf)
  1911. {
  1912.     ODUndoData *somThis = ODUndoGetData(somSelf);
  1913.     ODUndoMethodDebug("ODUndo","ODUndosomUninit");
  1914.  
  1915.     if (_fSystemUndo)
  1916.     {
  1917.         _fSystemUndo->RemoveClient(somSelf);
  1918.         
  1919.         if (_fSystemUndo->GetNumClients() == 0) // reclaim space.
  1920.         {
  1921.     //        WARN("Deleting system undo object.");
  1922.             ODDeleteObject(_fSystemUndo);
  1923.             SetSystemUndo(kODNULL);
  1924.         }
  1925.     }
  1926.     ODUndo_parents_somUninit(somSelf);
  1927. }
  1928. #if 0
  1929. //------------------------------------------------------------------------------
  1930. // ODUndo::Purge
  1931. //------------------------------------------------------------------------------
  1932.  
  1933. SOM_Scope ODSize  SOMLINK ODUndoPurge(ODUndo *somSelf, Environment *ev,
  1934.         ODSize size)
  1935. {
  1936.     ODUndoData *somThis = ODUndoGetData(somSelf);
  1937.     ODUndoMethodDebug("ODUndo","ODUndoPurge");
  1938.  
  1939.     ODSize purged = 0;
  1940.     ODVolatile(purged);
  1941.     
  1942.     SOM_TRY
  1943.         if (_fSystemUndo) {
  1944.             purged =  _fSystemUndo->Purge(size);
  1945.         }
  1946.         else
  1947.             purged =  0;
  1948.  
  1949.         purged += parent_Purge(somSelf,ev,size);
  1950.     SOM_CATCH_ALL
  1951.         WARN("Error %ld trying to purge in ODUndoPurge",ErrorCode());
  1952.         SetErrorCode(kODNoError);        // dh - Eat the exception; Purge should not 
  1953.                                         // propagate it because clients function
  1954.                                         // fine whether memory was purged or not.
  1955.     SOM_ENDTRY
  1956.  
  1957.     return purged;
  1958. }
  1959. #endif /* 0 */
  1960. //------------------------------------------------------------------------------
  1961. // ODUndo::AddActionToHistory
  1962. //------------------------------------------------------------------------------
  1963.  
  1964. SOM_Scope void  SOMLINK ODUndoAddActionToHistory(ODUndo *somSelf, Environment *ev,
  1965.         ODPart* whichPart,
  1966.         ODActionData* actionData,
  1967.         ODActionType actionType,
  1968.         ODName* undoActionLabel,
  1969.         ODName* redoActionLabel)
  1970. {
  1971.     ODUndoData *somThis = ODUndoGetData(somSelf);
  1972.     ODUndoMethodDebug("ODUndo","ODUndoAddActionToHistory");
  1973.  
  1974.     WASSERT_IS_PART_WRAPPER( ev, whichPart );
  1975.  
  1976.     SOM_TRY
  1977.  
  1978.     if (_fSystemUndo)
  1979.         _fSystemUndo->AddActionToHistory(whichPart, actionData, actionType,
  1980.                                         undoActionLabel, redoActionLabel);
  1981.     else
  1982.         THROW(kODErrOutOfMemory);
  1983.  
  1984.     SOM_CATCH_ALL
  1985.     SOM_ENDTRY
  1986. }
  1987.  
  1988. //------------------------------------------------------------------------------
  1989. // ODUndo::Undo
  1990. //------------------------------------------------------------------------------
  1991.  
  1992. SOM_Scope void  SOMLINK ODUndoUndo(ODUndo *somSelf, Environment *ev)
  1993. {
  1994.     ODUndoData *somThis = ODUndoGetData(somSelf);
  1995.     ODUndoMethodDebug("ODUndo","ODUndoUndo");
  1996.  
  1997.     SOM_TRY
  1998.  
  1999.     if (_fSystemUndo)
  2000.         _fSystemUndo->Undo();
  2001.     else
  2002.         THROW(kODErrEmptyStack);
  2003.  
  2004.     SOM_CATCH_ALL
  2005.     SOM_ENDTRY
  2006. }
  2007.  
  2008. //------------------------------------------------------------------------------
  2009. // ODUndo::Redo
  2010. //------------------------------------------------------------------------------
  2011.  
  2012. SOM_Scope void  SOMLINK ODUndoRedo(ODUndo *somSelf, Environment *ev)
  2013. {
  2014.     ODUndoData *somThis = ODUndoGetData(somSelf);
  2015.     ODUndoMethodDebug("ODUndo","ODUndoRedo");
  2016.  
  2017.     SOM_TRY
  2018.  
  2019.     if (_fSystemUndo)
  2020.         _fSystemUndo->Redo();
  2021.     else
  2022.         THROW(kODErrEmptyStack);
  2023.  
  2024.     SOM_CATCH_ALL
  2025.     SOM_ENDTRY
  2026. }
  2027.  
  2028. //------------------------------------------------------------------------------
  2029. // ODUndo::MarkActionHistory
  2030. //------------------------------------------------------------------------------
  2031.  
  2032. SOM_Scope void  SOMLINK ODUndoMarkActionHistory(ODUndo *somSelf, Environment *ev)
  2033. {
  2034.     ODUndoData *somThis = ODUndoGetData(somSelf);
  2035.     ODUndoMethodDebug("ODUndo","ODUndoMarkActionHistory");
  2036.  
  2037.     SOM_TRY
  2038.  
  2039.     if (_fSystemUndo)
  2040.         _fSystemUndo->MarkActionHistory();
  2041.     else
  2042.         THROW(kODErrCannotMarkAction);
  2043.  
  2044.     SOM_CATCH_ALL
  2045.     SOM_ENDTRY
  2046. }
  2047.  
  2048. //------------------------------------------------------------------------------
  2049. // ODUndo::ClearActionHistory
  2050. //------------------------------------------------------------------------------
  2051.  
  2052. SOM_Scope void  SOMLINK ODUndoClearActionHistory(ODUndo *somSelf, Environment *ev,
  2053.         ODRespectMarksChoices respectMarks)
  2054. {
  2055.     ODUndoMethodDebug("ODUndo","ODUndoClearActionHistory");
  2056.     ODUndoData *somThis = ODUndoGetData(somSelf);
  2057.  
  2058.     SOM_TRY
  2059.  
  2060.     if (_fSystemUndo)
  2061.         _fSystemUndo->ClearActionHistory(respectMarks);
  2062.  
  2063.     SOM_CATCH_ALL
  2064.     SOM_ENDTRY
  2065. }
  2066.  
  2067. //------------------------------------------------------------------------------
  2068. // ODUndo::ClearRedoHistory
  2069. //------------------------------------------------------------------------------
  2070.  
  2071. SOM_Scope void  SOMLINK ODUndoClearRedoHistory(ODUndo *somSelf, Environment *ev)
  2072. {
  2073.     ODUndoMethodDebug("ODUndo","ODUndoClearRedoHistory");
  2074.     ODUndoData *somThis = ODUndoGetData(somSelf);
  2075.  
  2076.     SOM_TRY
  2077.  
  2078.     if (_fSystemUndo)
  2079.         _fSystemUndo->ClearRedoHistory();
  2080.  
  2081.     SOM_CATCH_ALL
  2082.     SOM_ENDTRY
  2083. }
  2084.  
  2085. //------------------------------------------------------------------------------
  2086. // ODUndo::PeekUndoHistory
  2087. //------------------------------------------------------------------------------
  2088.  
  2089. SOM_Scope ODBoolean  SOMLINK ODUndoPeekUndoHistory(ODUndo *somSelf, Environment *ev,
  2090.         ODPart** part,
  2091.         ODActionData* actionData,
  2092.         ODActionType* actionType,
  2093.         ODName* actionLabel)
  2094. {
  2095.     ODUndoMethodDebug("ODUndo","ODUndoPeekUndoHistory");
  2096.     ODUndoData *somThis = ODUndoGetData(somSelf);
  2097.  
  2098.     SOM_TRY
  2099.  
  2100.     if (_fSystemUndo)
  2101.         return _fSystemUndo->PeekUndoHistory(part, actionData, actionType,
  2102.                                                 actionLabel);
  2103.     else
  2104.         return kODFalse;
  2105.  
  2106.     SOM_CATCH_ALL
  2107.     SOM_ENDTRY
  2108.     return kODFalse;
  2109. }
  2110.  
  2111. //------------------------------------------------------------------------------
  2112. // ODUndo::PeekRedoHistory
  2113. //------------------------------------------------------------------------------
  2114.  
  2115. SOM_Scope ODBoolean  SOMLINK ODUndoPeekRedoHistory(ODUndo *somSelf, Environment *ev,
  2116.         ODPart** part,
  2117.         ODActionData* actionData,
  2118.         ODActionType* actionType,
  2119.         ODName* actionLabel)
  2120. {
  2121.     ODUndoMethodDebug("ODUndo","ODUndoPeekRedoHistory");
  2122.     ODUndoData *somThis = ODUndoGetData(somSelf);
  2123.  
  2124.     SOM_TRY
  2125.  
  2126.     if (_fSystemUndo)
  2127.         return _fSystemUndo->PeekRedoHistory(part, actionData, actionType,
  2128.                                                 actionLabel);
  2129.     else
  2130.         return kODFalse;
  2131.  
  2132.     SOM_CATCH_ALL
  2133.     SOM_ENDTRY
  2134.     return kODFalse;
  2135. }
  2136.  
  2137. //------------------------------------------------------------------------------
  2138. // ODUndo::AbortCurrentTransaction
  2139. //------------------------------------------------------------------------------
  2140.  
  2141. SOM_Scope void  SOMLINK ODUndoAbortCurrentTransaction(ODUndo *somSelf, Environment *ev)
  2142. {
  2143.     ODUndoMethodDebug("ODUndo","ODUndoAbortCurrentTransaction");
  2144.     ODUndoData *somThis = ODUndoGetData(somSelf);
  2145.  
  2146.     SOM_TRY
  2147.  
  2148.     if (_fSystemUndo)
  2149.         _fSystemUndo->AbortCurrentTransaction();
  2150.  
  2151.     SOM_CATCH_ALL
  2152.     SOM_ENDTRY
  2153. }
  2154.  
  2155.